/**
 * Copyright 2021 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <gtest/gtest.h>
#include "buffer_pool.h"

namespace ge {
class BufferPoolUt : public testing::Test {

};

TEST_F(BufferPoolUt, add_str_ok) {
  BufferPool bp;
  PoolOffset offset_s1;
  void *pool_s1;
  {
    std::string s1("x");
    offset_s1 = bp.AddBuffer(s1.c_str(), s1.size() + 1);
    pool_s1 = bp.GetBuffer(offset_s1);
  }
  EXPECT_NE(pool_s1, nullptr);
  EXPECT_STREQ(static_cast<char *>(pool_s1), "x");

  void *pool_start = bp.GetBase();
  size_t pool_len = bp.GetLen();
  EXPECT_GE(pool_s1, pool_start);
  EXPECT_LE(static_cast<uint8_t *>(pool_s1) + 2, static_cast<uint8_t *>(pool_start) + pool_len);
  EXPECT_LE(bp.GetLen(), bp.GetCapability());
}

TEST_F(BufferPoolUt, AddNullptrFailed) {
  BufferPool bp;
  PoolOffset offset_s1;

  std::string s1("x");
  EXPECT_NE(bp.AddBuffer(s1.c_str(), s1.size() + 1), kInvalidOffset);
  EXPECT_EQ(bp.AddBuffer(nullptr, s1.size() + 1), kInvalidOffset);
}

TEST_F(BufferPoolUt, add_multiple_str_ok) {
  BufferPool bp;
  PoolOffset offset_s1, offset_s2, offset_s3;
  void *pool_s1, *pool_s2, *pool_s3;
  {
    std::string s1("x");
    offset_s1 = bp.AddBuffer(s1.c_str(), s1.size() + 1);

    std::string s2("y");
    offset_s2 = bp.AddBuffer(s2.c_str(), s2.size() + 1);

    std::string s3("bias");
    offset_s3 = bp.AddBuffer(s3.c_str(), s3.size() + 1);

    pool_s1 = bp.GetBuffer(offset_s1);
    pool_s2 = bp.GetBuffer(offset_s2);
    pool_s3 = bp.GetBuffer(offset_s3);
  }

  void *pool_start = bp.GetBase();
  size_t pool_len = bp.GetLen();
  EXPECT_GE(pool_s1, pool_start);
  EXPECT_LE(static_cast<uint8_t *>(pool_s1) + 2, static_cast<uint8_t *>(pool_start) + pool_len);
  EXPECT_GE(pool_s2, pool_start);
  EXPECT_LE(static_cast<uint8_t *>(pool_s2) + 2, static_cast<uint8_t *>(pool_start) + pool_len);
  EXPECT_GE(pool_s3, pool_start);
  EXPECT_LE(static_cast<uint8_t *>(pool_s3) + 5, static_cast<uint8_t *>(pool_start) + pool_len);

  EXPECT_NE(pool_s1, nullptr);
  EXPECT_STREQ(static_cast<char *>(pool_s1), "x");
  EXPECT_NE(pool_s2, nullptr);
  EXPECT_STREQ(static_cast<char *>(pool_s2), "y");
  EXPECT_NE(pool_s3, nullptr);
  EXPECT_STREQ(static_cast<char *>(pool_s3), "bias");
}

TEST_F(BufferPoolUt, expand_ok) {
  BufferPool bp(1);
  PoolOffset offset_s1, offset_s2;
  void *pool_s1, *pool_s2;
  {
    std::string s1("x");
    std::string s2("bias");
    offset_s1 = bp.AddBuffer(s1.c_str(), s1.size() + 1);
    EXPECT_LE(bp.GetLen(), bp.GetCapability());
    offset_s2 = bp.AddBuffer(s2.c_str(), s2.size() + 1);
    EXPECT_LE(bp.GetLen(), bp.GetCapability());

    pool_s1 = bp.GetBuffer(offset_s1);
    pool_s2 = bp.GetBuffer(offset_s2);
  }

  void *pool_start = bp.GetBase();
  size_t pool_len = bp.GetLen();
  EXPECT_GE(pool_s1, pool_start);
  EXPECT_LE(static_cast<uint8_t *>(pool_s1) + 2, static_cast<uint8_t *>(pool_start) + pool_len);
  EXPECT_GE(pool_s2, pool_start);
  EXPECT_LE(static_cast<uint8_t *>(pool_s2) + 2, static_cast<uint8_t *>(pool_start) + pool_len);

  EXPECT_NE(pool_s1, nullptr);
  EXPECT_STREQ(static_cast<char *>(pool_s1), "x");
  EXPECT_NE(pool_s2, nullptr);
  EXPECT_STREQ(static_cast<char *>(pool_s2), "bias");
}

TEST_F(BufferPoolUt, ExpandOverFlow) {
  BufferPool bp(1);
  PoolOffset offset_s1, offset_s2;

  std::string s1("x");
  std::string s2("bias");
  offset_s1 = bp.AddBuffer(s1.c_str(), s1.size() + 1);
  offset_s2 = bp.AddBuffer(s2.c_str(), SIZE_MAX);

  EXPECT_NE(offset_s1, kInvalidOffset);
  EXPECT_EQ(offset_s2, kInvalidOffset);
}

TEST_F(BufferPoolUt, GetInvalidOffset) {
  BufferPool bp(1);
  PoolOffset offset_s1, offset_s2;

  std::string s1("x");
  std::string s2("bias");
  offset_s1 = bp.AddBuffer(s1.c_str(), s1.size() + 1);
  offset_s2 = bp.AddBuffer(s2.c_str(), s2.size() + 1);

  EXPECT_EQ(bp.GetBuffer(bp.GetLen()), nullptr);
  EXPECT_EQ(bp.GetBuffer(bp.GetLen() + 1), nullptr);
  EXPECT_EQ(bp.GetBuffer(kInvalidOffset), nullptr);
  EXPECT_NE(bp.GetBuffer(offset_s1), nullptr);
  EXPECT_NE(bp.GetBuffer(offset_s2), nullptr);
}
}